package com.hainan.bike.util;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.enterprisedt.net.ftp.FTPClient;
import com.enterprisedt.net.ftp.FTPConnectMode;
import com.enterprisedt.net.ftp.FTPException;
import com.enterprisedt.net.ftp.FTPMessageCollector;
import com.enterprisedt.net.ftp.FTPTransferType;
import com.hainan.bike.cache.StandardOSCache;
import com.opensymphony.oscache.base.NeedsRefreshException;



/**
 * FTP公共方法
 * 
 * @author 钟伟
 * @date Jun 16, 2009
 */
public class FTPKit {
	private static Logger logger = Logger.getLogger(FTPKit.class);
	
	private static String CMS_FTP_CONFIG = FTPKit.class.getResource("/").toString().substring(6)+"config/ftp_config.xml";// FTP配置文件引用路径

	private String host;
	private String user;
	private String password;
	private String connectMode;
	private String transferType;
	private int timeout;

	private FTPClient ftp = null;

	private ConfigVO configVo = null;
	
	public static final String CACHE_KEY_FTP_CONFIG = "cache_ftp_config";
	
	
	/**
	 * Constructor with args
	 * 
	 * @param ftpId
	 */
	public FTPKit(String ftpId) {
		Map<String, ConfigVO> configMap = this.getFTPConfig();
		if (configMap != null && configMap.containsKey(ftpId)) {
			configVo = configMap.get(ftpId);

			host = configVo.getHost();
			user = configVo.getUser();
			password = configVo.getPassword();
			connectMode = configVo.getConnectMode();
			transferType = configVo.getTransferType();
			timeout = configVo.getTimeout();
		} else {
			logger.error("[FTP配置]没有找到FTP_ID=[" + ftpId + "]的配置信息!");
		}
	}

	/**
	 * 获取文件夹下文件名称
	 * 
	 * @param directory
	 * @return
	 */
	public String[] getFileList(String directory) {
		String[] filesName = new String[0];
		if (this.connectFtp()) {
			try {
				String[] directories = directory.split(File.separator.equals("/") ? "/" : "\\\\");
				for(int i=0;i<directories.length;i++){
					ftp.chdir(directories[i]);
				}
				filesName = ftp.dir();
			} catch (Exception e) {
				logger.error("[FTP配置]获取文件夹下文件名称异常：", e);
			} finally {
				this.quitFtp();
			}
		}
		return filesName;
	}

	/**
	 * 从FTP下载单个文件
	 * 
	 * @param localPath
	 * @param remoteFile
	 * @return
	 */
	public boolean downLoadFile(String localPath, String remoteFile, String remoteDir) {
		// 连接FTP
		if (this.connectFtp()) {
			try {
				ftp.chdir(remoteDir);
				// 下载文件
				ftp.get(localPath, remoteFile);
			} catch (Exception e) {
				logger.error("[FTP配置]从FTP下载文件操作出错：" + e.getMessage());
				return false;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return true;
		}
		return false;
	}
	
	/**
	 * 从FTP删除单个文件
	 * 
	 * @param remoteFile
	 * 				删除的文件名
	 * @param remoteDir
	 * 				删除的路径
	 * @return
	 */
	public boolean deleteFile(String remoteFile, String remoteDir) {
		// 连接FTP
		if (this.connectFtp()) {
			try {
				String[] directories = remoteDir.split(File.separator.equals("/") ? "/" : "\\\\");
				for(int i=0;i<directories.length;i++){
					ftp.chdir(directories[i]);
				}
				// 下载文件
				remoteFile = remoteFile.replace("/", File.separator);
				String remoteFileName=remoteFile.substring(remoteFile.lastIndexOf(File.separator)+1);
				ftp.delete(remoteFileName);
			} catch (Exception e) {
				logger.error("[FTP配置]从FTP删除文件操作出错：" + e.getMessage());
				return false;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return true;
		}
		return false;
	}
	

	/**
	 * 批量FTP下载
	 * 
	 * @param map
	 * @return
	 */
	public boolean downLoadfile(Map<String, String> map) {
		if (this.connectFtp()) {
			try {
				Iterator<String> iter = map.keySet().iterator();
				while (iter.hasNext()) {
					String remoteFile = iter.next();
					String localPath = map.get(remoteFile);
					try {
						ftp.get(localPath, remoteFile);
					} catch (Exception e) {
						logger.error("[FTP配置]FTP批量下载文件操作出错, 文件名称=[" + remoteFile + "]", e);
					}
				}
			} catch (Exception e) {
				logger.error("[FTP配置]从FTP批量下载文件操作出错：", e);
				return false;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return true;
		}
		return false;
	}
	
	
	/**
	 * 获取上传文件的字节码
	 * 
	 * @param map
	 * @return
	 * @throws Exception 
	 */
	public byte[] getUpLoadfileBytes(String targetFile) throws Exception {
		if (this.connectFtp()) {
			try {
					try {
						byte[] ist = ftp.get(targetFile);
						return ist;
					} catch (Exception e) {
						logger.error("[FTP配置]FTP获取远程文件字节出错, 文件名称=[" + targetFile + "]", e);
					}
			} catch (Exception e) {
				logger.error("[FTP配置]FTP获取远程文件字节出错：", e);
				throw e;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return null;
		}
		return null;
	}
	
	/**
	 * 获取上传文件的字节码
	 * 
	 * @param map
	 * @return
	 * @throws Exception 
	 */
	public String upLoadfileByBytes(byte[] bytes, String remoteFile) throws Exception {
		if (this.connectFtp()) {
			try {    
			    String directory = remoteFile.substring(0,remoteFile.lastIndexOf("/"));
				directory = directory.replace("/", File.separator);
				try {
					// 指向目标文件目录
					ftp.chdir(directory);
				} catch (FTPException e1) {
					logger.info("[FTP配置]文件目录不存在：", e1);
					if (logger.isInfoEnabled()) {
						logger.info("[FTP配置]创建文件目录" + directory);
					}
					// 目标文件目录不存在，创建文件目录
					String[] dirs = directory.split(File.separator.equals("/") ? "/" : "\\\\");
					if (dirs.length > 1) {
						// 多级目录
						for (int i = 0, l = dirs.length; i < l; i++) {
							if(dirs[i] != null && !dirs[i].equals("")){
								try {
									ftp.chdir(dirs[i]);
								} catch (FTPException ee) {
									ftp.mkdir(dirs[i]);
									ftp.chdir(dirs[i]);
								}
							}
						}
					} else {
						// 只有一级目录
						ftp.mkdir(directory);
						ftp.chdir(directory);
					}
				}
					try {
						String fileName=remoteFile.substring(remoteFile.lastIndexOf("/")+1);
						return ftp.put(bytes, fileName);
					} catch (Exception e) {
						logger.error("[FTP配置]FTP根据字节码上传文件出错, 文件名称=[" + remoteFile + "]", e);
						throw e;
					}
			} catch (Exception e) {
				logger.error("[FTP配置]FTP根据字节码上传文件出错：", e);
				throw e;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
		}
		return null;
	}
   
	/**
	 * 批量上传文件至ftp
	 * 
	 * @param fileList
	 *            文件名(file_name)
	 * @param directory
	 *            ftp存放文件的目录
	 * @param localPath
	 *            本地存放文件的目录
	 * @return
	 */
	public boolean upLoadFile(List<String> fileList, String directory, String localPath) {
		if (this.connectFtp()) {
			try {
				directory = directory.replace("/", File.separator);
				try {
					// 指向目标文件目录
					ftp.chdir(directory);
				} catch (FTPException e1) {
					logger.info("[FTP配置]文件目录不存在：", e1);
					if (logger.isInfoEnabled()) {
						logger.info("[FTP配置]创建文件目录" + directory);
					}
					// 目标文件目录不存在，创建文件目录
					String[] dirs = directory.split(File.separator.equals("/") ? "/" : "\\\\");
					if (dirs.length > 1) {
						// 多级目录
						for (int i = 0, l = dirs.length; i < l; i++) {
							if(dirs[i] != null && !dirs[i].equals("")){
								try {
									ftp.chdir(dirs[i]);
								} catch (FTPException ee) {
									ftp.mkdir(dirs[i]);
									ftp.chdir(dirs[i]);
								}
							}
						}
					} else {
						// 只有一级目录
						ftp.mkdir(directory);
						ftp.chdir(directory);
					}
				}
				// 上传文件
				for (Object oList : fileList) {
					String fileName = oList.toString();
					try {

						String path = localPath + fileName;
						// 执行文件上传操作
						ftp.put(path, fileName);
					} catch (Exception e2) {
						logger.error("[FTP配置]批量上传文件至FTP操作出错，文件名称=[" + fileName + "]", e2);
					}
				}
			} catch (Exception e) {
				logger.error("[FTP配置]批量上传文件至ftp异常：", e);
				return false;
			} finally {
				this.quitFtp();
			}
			return true;
		}
		return false;
	}

	/**
	 * 上传单个文件至FTP服务器
	 * 
	 * @param localFile
	 *            要上传至FTP的本地文件（包括本地路径）
	 * @param fileName
	 *            上传至FTP后的文件名
	 * @param directory
	 *            ftp存放文件的目录
	 * @return
	 */
	public boolean upLoadFile(String localFile, String fileName, String directory) {
		// 连接FTP
		if (this.connectFtp()) {
			try {
				directory = directory.replace("/", File.separator);
				try {
					// 指向目标文件目录
					ftp.chdir(directory);
				} catch (FTPException e) {
					logger.info("[FTP配置]文件目录不存在：", e);
					if (logger.isInfoEnabled()) {
						logger.info("[FTP配置]创建文件目录" + directory);
					}
					// 目标文件目录不存在，创建文件目录
					String[] dirs = directory.split(File.separator.equals("/") ? "/" : "\\\\");
					if (dirs.length > 1) {
						// 多级目录
						for (int i = 0, l = dirs.length; i < l; i++) {
							if(dirs[i] != null && !dirs[i].equals("")){
								try {
									ftp.chdir(dirs[i]);
								} catch (FTPException ee) {
									ftp.mkdir(dirs[i]);
									ftp.chdir(dirs[i]);
								}
							}
							
						}
					} else {
						// 只有一级目录
						ftp.mkdir(directory);
						ftp.chdir(directory);
					}

				}
				// 执行文件上传操作
				ftp.put(localFile, fileName);
			} catch (Exception e) {
				logger.error("[FTP配置]上传文件至FTP操作出错：", e);

				e.printStackTrace();

				return false;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return true;
		}
		return false;
	}

	/**
	 * 上传文件InputStream
	 * 
	 * @param srcStream
	 * @param fileName
	 * @param directory
	 * @return
	 * @throws Exception 
	 */
	public boolean upLoadFile(InputStream srcStream, String fileName, String directory) throws Exception {
		// 连接FTP
		if (this.connectFtp()) {
			try {
				directory = directory.replace("/", File.separator);
				try {
					// 指向目标文件目录
					ftp.chdir(directory);
				} catch (FTPException e) {
					logger.info("[FTP配置]文件目录不存在：", e);
					if (logger.isInfoEnabled()) {
						logger.info("[FTP配置]创建文件目录" + directory);
					}
					// 目标文件目录不存在，创建文件目录
					String[] dirs = directory.split(File.separator.equals("/") ? "/" : "\\\\");
					if (dirs.length > 1) {
						// 多级目录
						for (int i = 0, l = dirs.length; i < l; i++) {
							if(dirs[i] != null && !dirs[i].equals("")){
								try {
									ftp.chdir(dirs[i]);
								} catch (FTPException ee) {
									ftp.mkdir(dirs[i]);
									ftp.chdir(dirs[i]);
								}
							}
						}
					} else {
						// 只有一级目录
						ftp.mkdir(directory);
						ftp.chdir(directory);
					}
				}
				// 执行文件上传操作
				ftp.put(srcStream, fileName);
			} catch (Exception e) {
				logger.error("[FTP配置]上传文件至FTP操作出错：", e);
				throw e;
			} finally {
				// 退出FTP
				this.quitFtp();
			}
			return true;
		}
		return false;
	}

	/**
	 * 关闭FTP连接
	 */
	private void quitFtp() {
		try {
			ftp.quit();
			ftp = null;
			configVo = null;
		} catch (Exception e) {
			logger.error("[FTP配置]关闭FTP连接操作出错：", e);
		}
	}

	/**
	 * 初始化FTP连接参数，连接FTP服务器
	 */
	private boolean connectFtp() {
		if (configVo != null) {
			ftp = new FTPClient();
			try {
				// set up client
				ftp.setRemoteHost(host);
				FTPMessageCollector listener = new FTPMessageCollector();
				ftp.setMessageListener(listener);
				ftp.setControlEncoding("GBK");
				ftp.setTimeout(timeout);
				// connect and config properties
				ftp.connect();
				ftp.login(user, password);
				ftp.setType(transferType.equalsIgnoreCase("ASCII") ? FTPTransferType.ASCII : FTPTransferType.BINARY);
				ftp.setConnectMode(connectMode.equalsIgnoreCase("ACTIVE") ? FTPConnectMode.ACTIVE
								: FTPConnectMode.PASV);
			} catch (IOException e) {
				logger.error("[FTP配置]初始化FTP连接IO出错：", e);
			} catch (FTPException e) {
				logger.error("[FTP配置]初始化FTP连接出错：", e);
			}
			return true;
		}
		return false;
	}

	/**
	 * 加载FTP配置文件
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	private Map<String, ConfigVO> loadConfig() {
		Map<String, ConfigVO> map = null;
		
		try {
			
			SAXReader read = new SAXReader();
			Document document = read.read(new File(CMS_FTP_CONFIG));;
			Element root = document.getRootElement();
			Iterator<Element> iter = root.elementIterator("ftp");
			int size = root.elements("ftp").size();
			if (size > 0) {
				map = new HashMap<String, ConfigVO>(size);
				
				while (iter.hasNext()) {
					ConfigVO vo = new ConfigVO();
					Element config = iter.next();
					vo.setFtpId(config.elementText("id"));
					System.out.println(""+vo.getFtpId());
					vo.setHost(config.elementText("host"));
					vo.setUser(config.elementText("user"));
					vo.setPassword(config.elementText("password"));
					vo.setConnectMode(config.elementText("connect_mode"));
					vo.setTransferType(config.elementText("transfer_type"));
					vo.setTimeout(Integer.parseInt(config.elementText("timeout")));
					map.put(vo.getFtpId(), vo);
				}
			}
		} catch (Exception e) {
			logger.error("[FTP配置]加载FTP配置文件异常：", e);
		} finally {
			
		}
		return map;
	}

	/**
	 * 缓存FTP配置文件
	 * 
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	private Map<String, ConfigVO> getFTPConfig() {
		StandardOSCache StandardOSCache = new StandardOSCache();
		System.out.println("缓存FTP配置文件");
		int refreshPeriod = 60; // 刷新间隔时间：1小时  60 * 60
		
		
		
		
		
		Map<String, ConfigVO> obj = null;
		try {
			System.out.println("读取缓存");
			obj = (Map<String, ConfigVO>) StandardOSCache. getFromCache(CACHE_KEY_FTP_CONFIG, refreshPeriod);
		} catch (NeedsRefreshException e) {
			System.out.println("读取原数据");
			obj = this.loadConfig();
			
			if (obj == null) {
				System.out.println("csd原数据");
				StandardOSCache.cancelUpdate(CACHE_KEY_FTP_CONFIG);
				obj = (Map<String, ConfigVO>) e.getCacheContent();
			}
			if (obj != null) {
				System.out.println("更新写入缓存");
				StandardOSCache.set(CACHE_KEY_FTP_CONFIG, obj);
			}
		}
		return obj;
	}

	/**
	 * FTP VO
	 */
	private class ConfigVO {
		private String ftpId;
		private String host;
		private String user;
		private String password;
		private String connectMode;
		private String transferType;
		private int timeout;

		/**
		 * @return the host
		 */
		public String getHost() {
			return host;
		}

		/**
		 * @param host
		 *            the host to set
		 */
		public void setHost(String host) {
			this.host = host;
		}

		/**
		 * @return the user
		 */
		public String getUser() {
			return user;
		}

		/**
		 * @param user
		 *            the user to set
		 */
		public void setUser(String user) {
			this.user = user;
		}

		/**
		 * @return the password
		 */
		public String getPassword() {
			return password;
		}

		/**
		 * @param password
		 *            the password to set
		 */
		public void setPassword(String password) {
			this.password = password;
		}

		/**
		 * @return the connectMode
		 */
		public String getConnectMode() {
			return connectMode;
		}

		/**
		 * @param connectMode
		 *            the connectMode to set
		 */
		public void setConnectMode(String connectMode) {
			this.connectMode = connectMode;
		}

		/**
		 * @return the transferType
		 */
		public String getTransferType() {
			return transferType;
		}

		/**
		 * @param transferType
		 *            the transferType to set
		 */
		public void setTransferType(String transferType) {
			this.transferType = transferType;
		}

		/**
		 * @return the timeout
		 */
		public int getTimeout() {
			return timeout;
		}

		/**
		 * @param timeout
		 *            the timeout to set
		 */
		public void setTimeout(int timeout) {
			this.timeout = timeout;
		}

		/**
		 * @return the ftpId
		 */
		public String getFtpId() {
			return ftpId;
		}

		/**
		 * @param ftpId
		 *            the ftpId to set
		 */
		public void setFtpId(String ftpId) {
			this.ftpId = ftpId;
		}
	};

	public static void main(String[] args) {
		// 下载文件directory.replace("/", File.separator);
		
		System.out.println(FTPKit.class.getResource("/").toString().substring(6)+"config/proxool.xml"); //相对路径方式
		
		FTPKit fTPKit = new FTPKit("ftp1"); 
	}

}
